package cn.xdf.docscan

import android.graphics.PointF
import android.graphics.RectF
import android.util.Log

/**
 * 基于原 m38.mfh.run 的思路做稳定性过滤：
 * - 将角点映射到预览坐标后，计算包围框与中心点
 * - 过滤异常大/小或跳变过大的结果
 * - 不做插值动画，仅做“只在稳定时显示”的门控
 */
class DetectionSmoother {
    private var lastAcceptedBounds: RectF? = null
    private var lastAcceptedCenter: PointF? = null
    private var lastAcceptTimeMs: Long = 0L
    private val TAG = "DetectionSmoother"
    fun reset() {
        lastAcceptedBounds = null
        lastAcceptedCenter = null
        lastAcceptTimeMs = 0L
    }

    /**
     * 返回是否接受该检测，以及必要时可替换后的角点（此处不替换，仅返回原角点）。
     */
    fun accept(corners: List<PointF>, viewWidth: Int, viewHeight: Int): Boolean {
        if (corners.size != 4 || viewWidth <= 0 || viewHeight <= 0) return false

        val bounds = computeBounds(corners)
        val viewW = viewWidth.toFloat()
        val viewH = viewHeight.toFloat()
        val viewArea = viewW * viewH
        val newArea = bounds.width() * bounds.height()
        val center = PointF(
            (bounds.left + bounds.right) / 2f,
            (bounds.top + bounds.bottom) / 2f
        )

        // 面积与越界过滤（参考原项目：空结果隐藏；此处加入强约束以抑制异常抖动/全屏）
        val tooLarge = bounds.width() > viewW * 1.2f || bounds.height() > viewH * 1.2f || (newArea / viewArea) > 0.95f
        val tooSmall = bounds.width() < viewW * 0.05f || bounds.height() < viewH * 0.05f
        Log.i(TAG, "过滤检测结果: tooLarge=$tooLarge, tooSmall=$tooSmall ")
        if (tooLarge || tooSmall) return false

        val last = lastAcceptedBounds
        val lastCenter = lastAcceptedCenter
        if (last != null && lastCenter != null) {
            val lastArea = last.width() * last.height()
            val areaJump = newArea > lastArea * 4f || newArea * 4f < lastArea
            val maxCenterDelta = 0.25f * viewW.coerceAtMost(viewH)
            val dx = center.x - lastCenter.x
            val dy = center.y - lastCenter.y
            val movedTooMuch = (dx * dx + dy * dy) > (maxCenterDelta * maxCenterDelta)
            if (areaJump || movedTooMuch) return false
        }

        lastAcceptedBounds = bounds
        lastAcceptedCenter = center
        lastAcceptTimeMs = System.currentTimeMillis()
        return true
    }

    private fun computeBounds(points: List<PointF>): RectF {
        var minX = Float.POSITIVE_INFINITY
        var minY = Float.POSITIVE_INFINITY
        var maxX = Float.NEGATIVE_INFINITY
        var maxY = Float.NEGATIVE_INFINITY
        for (p in points) {
            if (p.x < minX) minX = p.x
            if (p.y < minY) minY = p.y
            if (p.x > maxX) maxX = p.x
            if (p.y > maxY) maxY = p.y
        }
        return RectF(minX, minY, maxX, maxY)
    }

}


